package test.thread.lock ;

import java.util.ArrayList ;
import java.util.List ;
import java.util.concurrent.locks.Condition ;
import java.util.concurrent.locks.ReentrantLock ;

/**
 * 使用ReentrantLock选择提醒，来避免通知过早的问题
 * @author 80002165 @date 2017年5月4日 下午7:20:21
 */
public class P_C_ThreadLock {
    static class Service {
        ReentrantLock lock = new ReentrantLock() ;
        Condition productionCondition = lock.newCondition() ;// 生产条件
        Condition consumerCondition = lock.newCondition() ; // 消费条件
        
        List<String> production = new ArrayList<String>() ;
        
        public void productor() {
            try {
                lock.lock() ;
                while (production.size() == 1) {
                    System.out.println("还有库存，不需要生产！") ;
                    productionCondition.await() ;
                }
                
                System.out.println("生产一颗大力丸。孩儿们，享用吧！") ;
                production.add("大力丸") ;
                consumerCondition.signalAll() ;
            } catch (Exception e) {
                e.printStackTrace() ;
            } finally {
                lock.unlock() ;
            }
        }
        
        public void consume() {
            try {
                lock.lock() ;
                System.out.println(Thread.currentThread().getName() + "库存情况：" + production.size()) ;
                while (production.size() == 0) {
                    System.out.println(Thread.currentThread().getName() + "库存告急！库存告急！" + production.size()) ;
                    consumerCondition.await() ;
                }
                System.out.println(Thread.currentThread().getName() + "来一颗" + production.remove(0)) ;
                productionCondition.signal() ;
            } catch (Exception e) {
                e.printStackTrace() ;
            } finally {
                lock.unlock() ;
            }
        }
    }
    
    static class ProductionThread extends Thread {
        Service service ;
        
        public ProductionThread(Service service) {
            super("大力丸厂家") ;
            this.service = service ;
        }
        
        @Override
        public void run() {
            for (int i=0; i<10;i++) {
                service.productor() ;
            }
        }
    }
    
    static class ConsumerThread extends Thread {
        Service service ;
        
        public ConsumerThread(Service service, String name) {
            super(name) ;
            this.service = service ;
        }
        
        @Override
        public void run() {
            for (int i=0;i<20;i++) {
                service.consume() ;
            }
        }
    }
    
    public static void main(String[] args) {
        Service service = new Service() ;
        Thread productorThread = new ProductionThread(service) ;
        productorThread.start() ;
        for (int i = 0; i < 5; i++) {
            Thread consumerThread = new ConsumerThread(service, "t_" + i) ;
            consumerThread.start() ;
        }
    }
}
